use std::fmt::{Formatter};
use std::ptr::NonNull;
//use std::marker::PhantomData;

struct Node {
    val: i64,
    next: Option<NonNull<Node>>,
    prev: Option<NonNull<Node>>,
}


struct NonNullHepler{
}
impl NonNullHepler  {
    fn as_ref<T>(ptr: NonNull<T>) -> &'static T {
        unsafe { &*(ptr.as_ptr())}
    }
    fn as_ref_mut<T>(ptr: &mut NonNull<T>) -> &'static mut T {
        unsafe { ptr.as_mut()}
    }
    fn new_ptr<T> (t: T) -> NonNull<T> {
        unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(t))) }
    }
}





impl Node {
    fn new(val: i64, next: Option<NonNull<Node>>, prev: Option<NonNull<Node>>) -> Self {
        Node {
            val,
            next,
            prev
        }
    }
}


impl std::fmt::Display for Node {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        write!(f, "(val:{}", self.val)?;
        match self.next {
            None => write!(f, " n:{}", "none")?,
            Some(addr) => write!(f, " n:{:?}", addr)?,
        };
        match self.prev {
            None => write!(f, " p:{}", "none")?,
            Some(addr) => write!(f, " p:{:?}", addr)?,
        };
        write!(f, "{}", ")")
    }
}



struct LinkList {
    length: usize,
    head: Option<NonNull<Node>>,
    tail: Option<NonNull<Node>>,
    //marker: PhantomData<Box<Node>>
}
impl LinkList {
    fn new() -> Self {
        LinkList {
            length: 0,
            head: None,
            tail: None,
     //       marker: PhantomData,
        }
    }
    fn insert_at_head(&mut self, v: i64){
        //new node return ptr
        let node_ptr = Some(NonNullHepler::new_ptr(Node::new(v, self.head, None)));
        
        match self.head {
            None => self.tail = node_ptr,
            Some(mut head_ptr) =>  NonNullHepler::as_ref_mut(&mut head_ptr).prev = node_ptr,
        }
        self.head = node_ptr;
        self.length += 1;
    }
    fn get(&self, i: usize) -> Option<&'static i64> {
        let mut p = self.head;
        let mut count = i;
        loop {
            match p {
                None =>  { 
                    return None;
                },
                Some(node_ptr) => {
                    let node = NonNullHepler::as_ref(node_ptr);
                    if count == 0 {
                        return Some(&node.val);
                    }
                    count -= 1;
                    p = node.next;
                }
            }
        }
    }
}

impl std::fmt::Display for LinkList {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        write!(f, "len:{}, Next[", self.length)?;
        let mut p = self.head; //copy syntax
        loop {
            match p  {
                None  => { 
                    return write!(f, "]");
                },
                Some(node_ptr) => {
                    let node =  NonNullHepler::as_ref(node_ptr);
                    write!(f, "{} ", node)?;
                    p = node.next;     
                }
            }
        }
    }
}


#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn link_list_test(){
        let mut l = LinkList::new();
        l.insert_at_head(1);
        l.insert_at_head(2);
        l.insert_at_head(3);
        l.insert_at_head(4);
        println!("LinkList: {}", l);
        assert_eq!(Some(&4), l.get(0));
        assert_eq!(Some(&3), l.get(1));
        assert_eq!(Some(&2), l.get(2));
        assert_eq!(Some(&1), l.get(3));
        assert_eq!(None, l.get(4));
    }

    #[test]
    fn node_test(){
        let node = Node::new(10, None, None);
        println!("Node: {}", node);
    }
}
